<template>
    <div class="json-viewer">
        <div v-if="error" class="error-message">
            {{ error }}
        </div>
        <div v-else-if="!jsonString" class="empty-message">
            等待格式化...
        </div>
        <div v-else class="json-tree">
            <div v-for="(item, index) in visibleItems" :key="index" class="json-item"
                :style="{ marginLeft: item.level * 20 + 'px' }">
                <span v-if="item.hasChildren" class="toggle-btn" @click="toggleNode(item.id)">
                    {{ item.expanded ? '▼' : '▶' }}
                </span>
                <span v-else class="toggle-placeholder"></span>
                <span class="json-key" v-if="item.key" @contextmenu.prevent="showKeyContextMenu($event, item.key)">
                    {{ item.key }}:
                </span>
                <span :class="['json-value', item.type]"
                    @contextmenu.prevent="showValueContextMenu($event, item.value)">
                    {{ item.value }}
                    <span v-if="!item.expanded && item.childrenCount" class="preview">
                        {{ item.type === 'array' ? `[${item.childrenCount}]` : `` }}
                    </span>
                </span>
                <span v-if="item.comma">,</span>
            </div>
        </div>
        <!-- 右键菜单 -->
        <n-dropdown :show="showDropdown" :options="dropdownOptions" :x="dropdownX" :y="dropdownY"
            placement="bottom-start" @clickoutside="closeDropdown" @select="handleSelect" />
    </div>
</template>

<script setup lang="ts">
import { ref, watch, computed } from 'vue'
import view from '@renderer/util/ui/ViewUtil'

interface JsonItem {
    id: string
    key: string | null
    value: string
    level: number
    type: string
    comma: boolean
    hasChildren: boolean
    expanded: boolean
    childrenCount: number
    parentId: string | null
}

const props = defineProps<{
    jsonString: string
}>()

const error = ref<string>('')
const allItems = ref<JsonItem[]>([])
const expandedNodes = ref<Set<string>>(new Set())

// 计算可见的节点
const visibleItems = computed(() => {
    return allItems.value.filter(item => {
        if (!item.parentId) return true
        let currentId = item.parentId
        while (currentId) {
            if (!expandedNodes.value.has(currentId)) return false
            const parent = allItems.value.find(i => i.id === currentId)
            currentId = parent?.parentId || null
        }
        return true
    })
})

// 生成唯一ID
let idCounter = 0
const generateId = () => `node_${idCounter++}`

const toggleNode = (id: string) => {
    if (expandedNodes.value.has(id)) {
        expandedNodes.value.delete(id)
    } else {
        expandedNodes.value.add(id)
    }
}

const parseJson = (jsonStr: string) => {
    if (!jsonStr) {
        allItems.value = []
        expandedNodes.value.clear()
        return
    }

    try {
        const parsed = JSON.parse(jsonStr)
        const items: JsonItem[] = []
        idCounter = 0
        expandedNodes.value.clear()

        const processValue = (
            key: string | null,
            value: any,
            level: number,
            isLast: boolean,
            parentId: string | null
        ): string => {
            const currentId = generateId()

            // 如果是数组或对象，将其ID添加到expandedNodes中
            if ((Array.isArray(value) && value.length > 0) ||
                (typeof value === 'object' && value !== null && Object.keys(value).length > 0)) {
                expandedNodes.value.add(currentId)
            }

            if (Array.isArray(value)) {
                items.push({
                    id: currentId,
                    key,
                    value: '[',
                    level,
                    type: 'array',
                    comma: false,
                    hasChildren: value.length > 0,
                    expanded: true,  // 默认展开
                    childrenCount: value.length,
                    parentId
                })

                value.forEach((item, index) => {
                    processValue(null, item, level + 1, index === value.length - 1, currentId)
                })

                items.push({
                    id: generateId(),
                    key: null,
                    value: ']',
                    level,
                    type: 'bracket',
                    comma: !isLast,
                    hasChildren: false,
                    expanded: false,
                    childrenCount: 0,
                    parentId: currentId
                })
            } else if (typeof value === 'object' && value !== null) {
                const entries = Object.entries(value)
                items.push({
                    id: currentId,
                    key,
                    value: '{',
                    level,
                    type: 'object',
                    comma: false,
                    hasChildren: entries.length > 0,
                    expanded: true,  // 默认展开
                    childrenCount: entries.length,
                    parentId
                })

                entries.forEach(([k, v], index) => {
                    processValue(k, v, level + 1, index === entries.length - 1, currentId)
                })

                items.push({
                    id: generateId(),
                    key: null,
                    value: '}',
                    level,
                    type: 'bracket',
                    comma: !isLast,
                    hasChildren: false,
                    expanded: false,
                    childrenCount: 0,
                    parentId: currentId
                })
            } else {
                items.push({
                    id: currentId,
                    key,
                    value: typeof value === 'string' ? `"${value}"` : String(value),
                    level,
                    type: typeof value,
                    comma: !isLast,
                    hasChildren: false,
                    expanded: false,
                    childrenCount: 0,
                    parentId
                })
            }

            return currentId
        }

        processValue(null, parsed, 0, true, null)
        allItems.value = items
        error.value = ''
    } catch (e) {
        error.value = '无效的JSON格式，请检查输入'
        allItems.value = []
        expandedNodes.value.clear()
    }
}

watch(() => props.jsonString, (newValue) => {
    parseJson(newValue)
}, { immediate: true })

// 右键菜单相关
const showDropdown = ref(false)
const dropdownX = ref(0)
const dropdownY = ref(0)
const dropdownOptions = ref([
    {
        label: '复制',
        key: 'copy'
    }
])
const currentCopyText = ref('')

const showKeyContextMenu = (e: MouseEvent, key: string) => {
    dropdownX.value = e.clientX
    dropdownY.value = e.clientY
    showDropdown.value = true
    currentCopyText.value = key
}

const showValueContextMenu = (e: MouseEvent, value: string) => {
    dropdownX.value = e.clientX
    dropdownY.value = e.clientY
    showDropdown.value = true
    currentCopyText.value = value
}

const closeDropdown = () => {
    showDropdown.value = false
}

const handleSelect = (key: string) => {
    if (key === 'copy') {
        // 如果是字符串值，去掉首尾的引号
        const textToCopy = currentCopyText.value.startsWith('"') && currentCopyText.value.endsWith('"')
            ? currentCopyText.value.slice(1, -1)
            : currentCopyText.value

        navigator.clipboard.writeText(textToCopy).then(() => {
            view.alertSuccessMessage('复制成功')
        }).catch(() => {
            view.alertErrorMessage('复制失败')
        })
    }
    closeDropdown()
}
</script>

<style scoped>
.json-viewer {
    font-family: monospace;
    font-size: 14px;
    line-height: 1.5;
    padding: 12px;
    border-radius: 4px;
    overflow: auto;
    height: 80%;
}

.json-tree {
    margin-bottom: 50px;
}

.error-message {
    color: #dc2626;
}

.json-item {
    white-space: nowrap;
    display: flex;
    align-items: center;
}

.toggle-btn {
    cursor: pointer;
    width: 20px;
    user-select: none;
    color: #6b7280;
}

.toggle-btn:hover {
    color: #374151;
}

.toggle-placeholder {
    width: 20px;
}

.json-key {
    color: #2563eb;
    margin-right: 4px;
}

.json-value {
    color: #1f2937;
}

.json-value.string {
    color: #059669;
}

.json-value.number {
    color: #7c3aed;
}

.json-value.boolean {
    color: #7c3aed;
}

.json-value.bracket {
    color: #4b5563;
}

.json-value.null {
    color: #dc2626;
}

.preview {
    color: #6b7280;
    font-style: italic;
    margin-left: 4px;
}

.empty-message {
    color: #6b7280;
    font-style: italic;
}

.json-key,
.json-value {
    cursor: default;
    user-select: text;
}
</style>